package com.lx.boot.db;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lx.annotation.Note;
import com.lx.boot.OS;
import com.lx.entity.PageResult;
import com.lx.entity.Result;
import com.lx.util.LX;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import java.lang.reflect.Field;
import java.util.*;
import java.util.Map.Entry;

@Note("通用Controller")
public class BaseController<M extends MpMapper<T>, T> extends ServiceImpl<M,T> implements CommandLineRunner {
    @Autowired
    protected M baseMapper;

    protected Map<String,String> fieldMap = new HashMap<>();

    protected List<TableFieldInfo> uniqueFiledList = new ArrayList<>();

    protected TableInfo tableInfo;

    @Override
    public void run(String... args) throws Exception {
        tableInfo = TableInfoHelper.getTableInfo(this.entityClass);
        // 获取实体类对应的数据库字段名
        for (TableFieldInfo fieldInfo : tableInfo.getFieldList()) {
            fieldMap.put(fieldInfo.getProperty(), fieldInfo.getColumn());
            if (fieldInfo.getField().getAnnotation(UniqueCheck.class) != null){
                uniqueFiledList.add(fieldInfo);
            }
        }
    }

    @GetMapping("/listPage")
    @Schema(description = "查询分页列表")
    public Result<PageResult<T>> listPage(
            @Parameter(in = ParameterIn.QUERY, description = "分页current", required = true)  @NotNull(message = "分页current不能为空!") Long current
            , @Parameter(in = ParameterIn.QUERY, description = "分页size", required = true)  @NotNull(message = "分页size不能为空!") Long size
            , @Parameter(in = ParameterIn.QUERY, description = "过滤条件:使用{col1-eq:'val',col2-like:'val'}") String whereJson
            , @Parameter(in = ParameterIn.QUERY, description = "排序条件:使用'col1-asc,col2-desc'") String sort) {
        return Result.ok(new PageResult<>(baseMapper.selectPage(new Page(current,size),parseWhereSql(whereJson,sort))));
    }

    @GetMapping("/list")
    @Schema(description = "查询列表")
    public Result<List<T>> getList(
            @Parameter(in = ParameterIn.QUERY, description = "过滤条件:使用{col1-eq:'val',col2-like:'val'}") String whereJson
            , @Parameter(in = ParameterIn.QUERY, description = "排序条件:使用'col1-asc,col2-desc'") String sort) {
        return Result.ok(baseMapper.selectList(parseWhereSql(whereJson,sort)));
    }

    @GetMapping("/get")
    @Schema(description = "获取")
    public Result get(String id) {
        return Result.ok(baseMapper.selectById(id));
    }


    @PostMapping("/insert")
    @Schema(description = "新增")
    @Transactional
    public Result insert(@RequestBody @Valid T entity) {
        baseMapper.insert(entity);
        checkUnique(entity);
        return Result.ok();
    }

    private void checkUnique(T entity) {
        if (!uniqueFiledList.isEmpty()){
            QueryWrapper<T> queryWrapper = new QueryWrapper<>();
            for (TableFieldInfo v : uniqueFiledList) {
                try {
                    Field field =  v.getField();
                    field.setAccessible(true);
                    queryWrapper.eq(v.getColumn(),field.get(entity));
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
                List<T> systemUsers = baseMapper.selectList(queryWrapper);
                LX.exMsg(systemUsers.size()>1,"无法新增,数据已存在!");
            }
        }
    }

    /**
     * @author ylx 2024/9/12 09:29:08
     */
    @Transactional
    @PostMapping("/update")
    @Schema(description = "更新(未传入条件使用主键更新,参数:{col:'val',col1-eq:'val',col2-like:'val'})  set,eq,ne,like,leftlike,rightlike,notlike,between,in,notIn,isNull,isNotNull,gt,lt,ge,le")
    public Result update(@RequestBody Map<String,Object> map) {
        UpdateWrapper<T> updateWrapper = new UpdateWrapper<>();
        if(LX.isNotEmpty(map)){
            boolean useId = true; //使用主键更新
            for (Entry<String, Object> entry : map.entrySet()) {
                String[] split = entry.getKey().split("\\$");
                String column = fieldMap.get(split[0]);
                if (LX.isNotEmpty(column)){
                    Object val = entry.getValue();
                    String type = "set";
                    if (split.length>1){
                        type = split[1];
                        if (!"setNull".equals(type)){
                            useId = false;
                        }
                    }else{
                        if ("update_time".equals(column)){
                            val = new Date();
                        }else if ("update_user".equals(column)){
                            val = OS.getUserId();
                        }else if ("add_time".equals(column) || "add_user".equals(column)){
                            //新增人和时间无需更新
                            continue;
                        }
                    }
                    switch (type){
                        case "set"-> updateWrapper.set(column,val);
                        case "setNull"-> updateWrapper.set(column,null);
                        case "eq"-> updateWrapper.eq(column,val);
                        case "ne"-> updateWrapper.ne(column,val);
                        case "in"->updateWrapper.in(column,LX.toList(val));
                        case "notIn"->updateWrapper.notIn(column,LX.toList(val));
                        case "isNull"-> updateWrapper.isNull(column);
                        case "isNotNull"-> updateWrapper.isNotNull(column);
                        default -> {
                            if (LX.isNotEmpty(val)){ // 值不为空时处理!
                                switch (type){
                                    case "like"-> updateWrapper.like(column,val);
                                    case "leftlike"-> updateWrapper.likeLeft(column,val);
                                    case "rightlike"-> updateWrapper.likeRight(column,val);
                                    case "notlike"-> updateWrapper.notLike(column,val);
                                    case "between"->{
                                        List list = LX.toList(val);
                                        updateWrapper.between(column,list.get(0),list.get(1));
                                    }
                                    case "gt"-> updateWrapper.gt(column,val);
                                    case "lt"-> updateWrapper.lt(column,val);
                                    case "ge"-> updateWrapper.ge(column,val);
                                    case "le"-> updateWrapper.le(column,val);
                                }
                            }
                        }
                    }
                }
            }
            if (useId){
                //没有传入条件时 使用主键进行更新
                updateWrapper.eq(tableInfo.getKeyColumn(),map.get(tableInfo.getKeyProperty()));
            }
            baseMapper.update(updateWrapper);
            if (!uniqueFiledList.isEmpty()){
                QueryWrapper queryWrapper = new QueryWrapper();
                queryWrapper.select(uniqueFiledList.get(0).getColumn());
                for (TableFieldInfo fieldInfo : uniqueFiledList) {
                    queryWrapper.groupBy(fieldInfo.getColumn());
                    queryWrapper.having("count(0)>1");
                }
                List list = baseMapper.selectList(queryWrapper);
                LX.exMsg(!list.isEmpty(),"无法更新,数据已存在!");

            }
        }
        return Result.ok();
    }

    @GetMapping("/invalid")
    @Schema(description = "删除数据(依次判断 id, ids, whereJson)")
    public Result invalid(String id, String ids, String whereJson) {
        if (id != null){
            return Result.ok(baseMapper.deleteById(id));
        }
        if (ids != null){
            List list = LX.toList(ids);
            if (LX.isNotEmpty(list)){
                return Result.ok(baseMapper.deleteBatchIds(list));
            }
        }
        if (LX.isNotEmpty(whereJson)){
            return Result.ok(baseMapper.delete(parseWhereSql(whereJson, null)));
        }
        return Result.err("请传入删除条件");
    }
    @GetMapping("/delete")
    @Schema(description = "物理删除数据(依次判断 id, ids, whereJson)")
    public Result delete(String id, String ids, String whereJson) {
        if (id != null){
            return Result.ok(baseMapper.deleteAbsoluteById(id));
        }
        if (ids != null){
            List list = LX.toList(ids);
            if (LX.isNotEmpty(list)){
                return Result.ok(baseMapper.deleteAbsoluteBatchIds(list));
            }
        }
        if (LX.isNotEmpty(whereJson)){
            return Result.ok(baseMapper.deleteAbsolute(parseWhereSql(whereJson, null)));
        }
        return Result.err("请传入删除条件");
    }

    // 将前端参数转换为QueryWrapper
    //eq,ne,like,leftlike,rightlike,notlike,between,in,notIn,isNull,isNotNull,gt,lt,ge,le
    public QueryWrapper parseWhereSql(String whereJson,String sort){
        QueryWrapper queryWrapper = new QueryWrapper();
        if(LX.isNotEmpty(whereJson)){
            HashMap<String,Object> conditionList = LX.toMap(HashMap.class,whereJson);
            if(LX.isNotEmpty(conditionList)){
                conditionList.forEach((key,val)->{
                    String[] split = key.split("\\$");
                    String column = fieldMap.get(split[0]);
                    LX.exMsg(LX.isEmpty(column),"传入条件不存在请检查:"+split[0]);
                    String type = split.length>1?split[1]:"eq";
                    switch (type){
                        case "eq"-> queryWrapper.eq(column,val);
                        case "ne"-> queryWrapper.ne(column,val);
                        case "isNull"-> queryWrapper.isNull(column);
                        case "isNotNull"-> queryWrapper.isNotNull(column);
                        case "in"->queryWrapper.in(column,LX.toList(val));
                        case "notIn"->queryWrapper.notIn(column,LX.toList(val));
                        default ->{
                            if (LX.isNotEmpty(val)){ // 这些条件val不能为空
                                switch (type){
                                    case "like"-> queryWrapper.like(column,val);
                                    case "leftlike"-> queryWrapper.likeLeft(column,val);
                                    case "rightlike"-> queryWrapper.likeRight(column,val);
                                    case "notlike"-> queryWrapper.notLike(column,val);
                                    case "between"->{
                                        List list = LX.toList(val);
                                        queryWrapper.between(column,list.get(0),list.get(1));
                                    }
                                    case "gt"-> queryWrapper.gt(column,val);
                                    case "lt"-> queryWrapper.lt(column,val);
                                    case "ge"-> queryWrapper.ge(column,val);
                                    case "le"-> queryWrapper.le(column,val);
                                }
                            }
                        }
                    }
                });
            }
        }
        if(LX.isNotEmpty(sort)){
            String[] list = sort.split(",");
            for (String key : list) {
                String[] split = key.split("\\$");
                String column = fieldMap.get(split[0]);
                LX.exMsg(LX.isEmpty(column),"传入排序条件不存在请检查:"+split[0]);
                String type = split.length > 1 ? split[1] : "asc";
                switch (type) {
                    case "asc"-> queryWrapper.orderByAsc(column);
                    case "desc"-> queryWrapper.orderByDesc(column);
                    default -> LX.exMsg("排序-后使用asc或desc!");
                }
            }
        }

        return queryWrapper;
    }

}
